Appearance
本篇学习日志参考了 掘金文章(JavaScript新特性最全指南:ES2024 ~ ES2016 ) 与 MDN。 通过掘金文章提供罗列的新特性, 逐个在MDN查找后, 转换成本人熟悉的文章结构和记录风格。 因为本人学艺不精,在参数类型定义,及其他地方有优化空间。
ES2024
【类库】
isWellFormed() 单独代理项格式监测
String.prototype.isWellFormed()
字符串是否包含单独代理项 传递的字符串格式不正确, encodeURI 会抛出错误,可用该方法做预判
参数:/ 返回值:boolean
js
const illFormed = "https://example.com/search?q=\uD800";
try {
encodeURI(illFormed);
} catch (e) {
console.log(e); // URIError: URI malformed
}
if (illFormed.isWellFormed()) {
console.log(encodeURI(illFormed));
} else {
console.warn("Ill-formed strings encountered."); // Ill-formed strings encountered.
}resizable 二进制对象是否可调大小
ArrayBuffer.prototype.resizable
当创建实例时,设置了maxByteLength最大字节,则可调
返回值:boolean
js
const buffer = new ArrayBuffer(8, { maxByteLength: 16 });
if (buffer.resizable) {
console.log("缓冲区可以调整大小!");
buffer.resize(12);
}ES2023
【类库】
findLast() 反向寻找
Array.prototype.findLast()
反向在数组中寻找匹配元素,类似arr.find
参数:callback 回调参数:元素, 索引, 数组本身 返回值:元素 | undefined 注:只匹配第一个符合的元素
js
const inventory = [
{ name: "apples", quantity: 2 },
{ name: "bananas", quantity: 0 },
{ name: "fish", quantity: 1 },
{ name: "cherries", quantity: 5 },
];
// 库存低时返回 true
function isNotEnough(item) {
return item.quantity < 2;
}
console.log(inventory.findLast(isNotEnough));
// { name: "fish", quantity: 1 }findLastIndex() 反向寻找索引
Array.prototype.findLastIndex()
反向在数组中寻找匹配元素的索引,类似arr.findIndex
参数:callback 回调参数:遍历元素, 索引, 数组本身 返回值:索引 | -1 注:只匹配第一个符合的元素
js
function isPrime(element) {
if (element % 2 === 0 || element < 2) {
return false;
}
for (let factor = 3; factor <= Math.sqrt(element); factor += 2) {
if (element % factor === 0) {
return false;
}
}
return true;
}
console.log([4, 6, 8, 12].findLastIndex(isPrime)); // -1,没有找到
console.log([4, 5, 7, 8, 9, 11, 12].findLastIndex(isPrime)); // 5toReversed()数组翻转
Array.prototype.toReversed()
原本的reversed()方法,会改变原数组,该方法不改变
参数: / 返回值: 新数组 注:原数组不变
js
const items = [1, 2, 3];
console.log(items); // [1, 2, 3]
const reversedItems = items.toReversed();
console.log(reversedItems); // [3, 2, 1]
console.log(items); // [1, 2, 3]toSorted()数组排序
Array.prototype.toSorted()
原本的sort()方法,会改变原数组,该方法不改变
参数: undefind | callback 回调参数:上一个元素,下一个元素 返回值: 新数组 注:原数组不变
js
// 不传入函数
toSorted()
// 传入箭头函数
toSorted((a, b) => { /* … */ })
// 传入比较函数
toSorted(compareFn)
// 內联比较函数
toSorted(function compareFn(a, b) { /* … */ })
const months = ["Mar", "Jan", "Feb", "Dec"];
const sortedMonths = months.toSorted();
console.log(sortedMonths); // ['Dec', 'Feb', 'Jan', 'Mar']
console.log(months); // ['Mar', 'Jan', 'Feb', 'Dec']
const values = [1, 10, 21, 2];
const sortedValues = values.toSorted((a, b) => a - b);
console.log(sortedValues); // [1, 2, 10, 21]
console.log(values); // [1, 10, 21, 2]toSpliced()数组替换
Array.prototype.toSpliced()
原本的splice()方法,会改变原数组,该方法不改变
重载1:删除后续 参数: number开始索引
重载2:删除节选 参数: number开始索引, number删除长度,
重载3:替换节选 参数: number开始索引, number删除长度, element1插入内容1, element2插入内容2 elementN 返回值: 新数组 注:原数组不变
js
splice(start)
splice(start, deleteCount)
splice(start, deleteCount, item1)
splice(start, deleteCount, item1, item2, itemN)
const months = ["Jan", "Mar", "Apr", "May"];
// 在索引 1 处添加一个元素
const months2 = months.toSpliced(1, 0, "Feb");
console.log(months2); // ["Jan", "Feb", "Mar", "Apr", "May"]
// 从第 2 个索引开始删除两个元素
const months3 = months2.toSpliced(2, 2);
console.log(months3); // ["Jan", "Feb", "May"]
// 在索引 1 处用两个新元素替换一个元素
const months4 = months3.toSpliced(1, 1, "Feb", "Mar");
console.log(months4); // ["Jan", "Feb", "Mar", "May"]
// 原数组不会被修改
console.log(months); // ["Jan", "Mar", "Apr", "May"]with()数组修改
原本通过直接等号赋值数组索引,改变数组内容。 该方法是不改变数组版本
参数: number索引 any属性值 返回值:新数组 注: 索引为负数表示倒序查询 超过查询极限则报错
js
// 原本改变数组内容
const arr = [1, 2, 3];
arr[0] = 4; // [4, 2, 3]
const arr = [1, 2, 3, 4, 5];
console.log(arr.with(2, 6)); // [1, 2, 6, 4, 5]
console.log(arr); // [1, 2, 3, 4, 5]【语法】
node.js 执行js文件语法糖
#!/usr/bin/env node
命令行工具执行js文件,需要加上node前缀 在执行的js中首行添加该命令,可省去node前缀
js
// 添加后的js执行文件
#!/usr/bin/env node
console.log('hello')
// 例1
node ./test.js // 正常执行,未报错
// 例2
./index.js // 未添加时执行,报错
./index.js: line 1: syntax error near unexpected token "javascript"
./index.js: 1ine 1: `console.log("Javascript")`
// 例3
./index.js // 添加后执行,未报错允许Symbol作为WeakMap的键
原本WeakMap键值对的键只允许使用对象类型,现在允许使用Symbol类型
js
const weak = new WeakMap();
const key = Symbol('hello');
weak.set(key, 'world');ES2022
【类库】
at() 数组索引查询
Array.prototype.at()
同括号表示法,但可以使用负数。 适合在未知数组长度时,寻找最后一项。
参数:number索引 返回值:any数组元素
js
const arr = [1,2,3];
// old
arr[1]; // 2
arr[arr.length - 1] // 3
// now
arr.at(1); // 2
arr.at(-1); // 3hasOwn() 对象检查属性
Array.prototype.at()
Object的静态方法,用于确认对象有没有某个属性。 原本的hasOwnProperty方法,因为任何类型都能从原型链上找到,所以有了新版。 个人感受,纯属脱裤子放屁,需要确认的场景大多可以通过?.链式操作规避。
参数: object被检查对象 string属性名 返回值:boolean
js
const obj = {a: 1};
// old,通过原型链确认
obj.hasOwnProperty('a'); // true
// now
Object.hasOwn(obj,'a'); // true【语法】
class 属性定义简化
原本class定义属性需在constructor内定义,现在可以直接在外部定义。
js
// old
class X{
constructor(){
this.a = 'a';
}
}
// now
class X{
a = 'a';
}class 成员私有化
首字母#的属性无法被外部读取 在ES2022之前,并没有实际意义上的私有字段。大家形成一种默契,通常用下划线_开头的字段名来表示私有字段,但是这些字段还是可以手动更改的。 ES2022给我们提供了更加安全便捷的私有字段定义方法,就是以#开头命名的字段,都会被当成私有字段,在class外部是没办法直接读取、修改这些私有字段的。
js
class My {
#a = 'a';
b = 'b'
c;
constructor() {
this.c = this.#a + 'c';
};
};
const bob = new My();
console.log(bob.#a); // 报错
console.log(bob.b); // 'b'
console.log(bob.c); // 'ac'class 静态初始化块
用于在初始化时处理静态内容的一个代码块
js
class My {
a = 'a';
// now
static {
this.a = 'b'
}
}
const baobao = new My;
console.log(baobao.a); // 'a'
console.log(My.a); // 'b'await 可单独在外部
原本await必须在async函数内,现在可在 ES Modules模块化文件最外层直接使用。
js
try {
await fetch('url')
} catch {
// ...
}regexp/d 正则匹配范围修饰
新的修饰符,原本正则匹配只会返回开始匹配的索引index, 使用该修饰符时,多了获取匹配到内容的区间的属性indices。
js
const text = 'abbbcccddebc';
const reg = /bc/
const reg_has_d = /bc/d
// old
console.log(reg.exec(text))
// [ 'bc', index: 3, input: 'abbbcccddebc', groups: undefined ]
// now
console.log(reg_has_d.exec(text))
// [ 'bc', index: 3, input: 'abbbcccddebc', groups: undefined, indices: [ [ 3, 5 ], groups: undefined ] ]Error_cause错误传递
构造函数Error的第二个参数options,新增cause字段,用于将信息传递给下一个捕获的地方。
js
try {
await fetch('url')
.catch(err => {
throw new Error('no', { cause: 'is_err' })
});
} catch(e){
// old
console.log(e); // 一大串具体错误,适合调试,但不适合显示
// now
console.log(e.cause); // is_err
}ES2021
【类库】
replaceAll() 匹配替换全部
String.prototype.replaceAll()
等同于在replace时,第一个参数为正则时/g匹配
参数: string | regexp 匹配的内容 string | callback 替换内容 回调参数:与其他正则相关回调相同,不展开讲 返回值: 新字符串 注:如果使用regexp必须加/g全局匹配,否则报错
js
// old
'aabc'.replace(/a/, '哈哈') // 哈哈abc
'aabc'.replace('a', '哈哈') // 哈哈abc
'aabc'.replace(/a/g, '哈哈') // 哈哈哈哈bc
// now
'aabc'.replaceAll('a', '哈哈') // 哈哈哈哈bcany() 异步全部匹配
Promise.any()
Promise的静态方法,多个promise中获取最快的成功结果。 与Promise.race()不同的是,race求一个最快的结果不论好坏,any求一个最快的成功结果。
参数: promise实例1 promise实例2 promise实例N 返回值:整合后的promise实例,可直接用then链式调用。 注:catch部分在所有异步都失败时给出。
js
const promise1 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'quick')
setTimeout(reject, 90, 'quick')
});
const promise2 = new Promise((resolve) => setTimeout(resolve, 500, 'slow'));
Promise.any([promise1, promise2])
.then((value) => console.log('any:' + value)) // any: slow
.catch(() => console.log('err')); // 只有在两者都失败时才显示
Promise.race([promise1, promise2])
.then((value) => console.log('race:' + value))
.catch(() => console.log('race:' + 'err')); // race:errWeakRef 弱引用对象
疑似跟垃圾回收机制有关,weakRef对象被回收时不会被阻止
js
const obj = {a: 1};
const ref = new WeakRef(obj);
console.log(ref) // WeakRef {}
// 使用原型链方法deref获取对象
console.log(ref.deref()) // { a: 1 }
// 暂时想不到回收机制相关的应用场景,用例待验证【语法】
number_00 数字分隔符
意义不变,但使人类舒适
1_0 === 10; // true
7_00 - 1_00 // 600逻辑赋值运算符
若能短路到右边,则将右边赋值给左边 短路运算的复杂版,难搞,且使用场景不多(面试题!!!),不推荐用
js
// 或
var a = false;
var b = 2;
a ||= b;
// 左边为false,短路,执行右边
// 将右边的值赋值给左边
console.log(a); // 2
// 且
var a = 2;
var b = 0;
a &&= b;
// 左边为true,短路,执行右边
// 将右边赋值给左边
console.log(a); // 0
// ??
var a = null;
var b = 2;
// 左边为null或undef,执行右边
// 将右边赋值给左边
console.log(a); // 2ES2020
【类库】
matchAll() 正则查询全部
String.prototype.matchAll()
match()的增强版,返回值类似exec()的返回值
参数:string | regexp 匹配规则 返回值:Iterator迭代器 注:只想得到匹配的元素,建议使用结构更清晰的match
js
// old
'aabc'.match(/a/g); // ['a', 'a']
// now
// 通过展开运算符,化为数组结构
[...'aabc'.matchAll(/a/g)]; // [['a', index:0, input:'aabc',...], ['a', index: 1]]
// 通过next展开迭代器
const regexp = 'aabc'.matchAll('a');
console.log(reg.next()); // {done: false, value: ['a',index:0,input:...]};
console.log(reg.next()); // {done: false, value: ['a',index:1,input:...]};
console.log(reg.next()); // {done: true, value: undefined};allSettled() 异步全部匹配
Promise.allSettled()
all的增强版,当all执行过程中,有报错则会直接中断。 allSetLed则会返回状态和错误。
参数: promise实例1 promise实例2 promise实例N 返回值:{stats状态, value值}[ ]
js
const promise1 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'good_1')
setTimeout(reject, 190, 'err_1')
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'good_2')
setTimeout(reject, 400, 'err_2')
});
Promise.all([promise1, promise2]).then((value) => console.log(value));
// [ 'good_1', 'good_2' ]
Promise.allSettled([promise1, promise2]).then((value) => console.log(value));
// [{ status: 'fulfilled', value: 'good_1' },{ status: 'fulfilled', value: 'good_2' }]BigInt 大整型对象
原本js最大整数为 Math.pow(2, 53) -1,超出则精度丢失。
注:BigInt不可与number运算,但可比较
js
BigInt("0b11111111111111111111111111111111111111111111111111111");
BigInt(2) - BigInt(1); // 1n
1n === BigInt(1) // true
1n < 2 // true【语法】
import 动态导入
可以把import作为一个变量,动态导入,仅可在ES modules模块化js中使用 很好用,配合node.js的file模块,可以批量导入图片
js
// 被导入文件 test.js
export function haha() {
console.log('haha')
}
// 使用文件
const urlList = ['./test.js'];
urlList.forEach(url => {
import(url).then((module) => {
module.haha();
})
})
// hahaglobalThis全局对象
新的关键字,在node环境和游览器环境指向不同
js
window === globalThis // 游览器环境
global === globalthis // Node.js 环境?.可选操作符
使用点操作符,链式调用属性,若上一层未查询到,则直接报错。 该操作符可规避此类报错。
js
const obj = null;
obj.a; // 报错
obj?.a; // undefined空值合并运算符
类似 || 或运算,在此基础上,更语义化和严谨的方案。 只有左侧为 null 或 undefined 时,才返回右侧操作符。
js
// 或运算
0 || 1; // 1
null || 1: // 1
false || 1; // 1
// 因为左侧能隐式转换成false,所以返回右侧
// 空值合并运算
0 ?? 1; //0
false ?? 1; // false
null ?? 1; // 1
// 只有null和undefined可返回右侧,其余均返回左侧ES2019
【类库】
description 唯一值描述
Symbol.prototype.description
可快速获取symbol值的描述内容
返回值:value描述
js
Symbol("desc").toString(); // "Symbol(desc)"
Symbol("desc").description; // "desc"
Symbol("").description; // ""
Symbol().description; // undefined
// 内置通用(well-known)symbol
Symbol.iterator.toString(); // "Symbol(Symbol.iterator)"
Symbol.iterator.description; // "Symbol.iterator"
// global symbols
Symbol.for("foo").toString(); // "Symbol(foo)"
Symbol.for("foo").description; // "foo"formEntries() 对象转二维数组
Object.fromEntries()
对象的静态方法,二维数组 转 对象。 entries的逆向转换。
参数:array二维数组 | Map键值对 返回值:object对象 注:Map的键如果是对象,则返回object Object
js
// 正常使用
const entries = [
['foo', 'bar'],
['baz', 42],
];
const obj = Object.fromEntries(entries);
console.log(obj); // { foo: "bar", baz: 42 }
const entries = new Map([
['foo', 'bar'],
['baz', 42],
]);
const obj = Object.fromEntries(entries);
console.log(obj); // { foo: "bar", baz: 42 }
// map的键是对象
const entries = new Map([
[{a:1}, 'bar'],
['baz', 42],
]);
const obj = Object.fromEntries(entries);
console.log(obj); // { [object Object]: "bar", baz: 42 }
// 值是对象
const entries = new Map([
['foo', {a:1}],
['baz', 42],
]);
const obj = Object.fromEntries(entries);
console.log(obj); // { foo: { a: 1 }, baz: 42 }entries() 二维数组转对象
Object.entries()
对象的静态方法,对象 转 二维数组。 fromEntries的逆向转换。
参数:object对象 返回值:array二维数组
js
const obj = {
a: 'string',
b: 1,
};
console.log(Object.entries(obj));
// [["a", "string"], ["b", 1]]trimStart() 消除前空格
String.prototype.trimStart()
trim方法的细化版本,后面的空格不会处理
参数:/ 返回值:string 新字符串
js
const greeting = ' a ';
console.log(greeting); // " a "
console.log(greeting.trimStart()); // "a "trimEnd() 消除前空格
String.prototype.trimEnd()
trim方法的细化版本,前面的空格不会处理
参数:/ 返回值:string 新字符串
js
const greeting = ' a ';
console.log(greeting); // " a "
console.log(greeting.trimEnd()); // " a"【语法】
catch 参数可选
原本catch必须有参数结构,现在可以省略
js
// old
try{
} catch (err){
};
// now
try{
} catch {
}Function toString() 函数返回增强
原本返回函数源码时,会删除注释和空格
js
const fn = () => {
// 注释
console.log(1);
}
console.log(fn.toString());
// 执行结果
() => {
// 注释
console.log(1);
}JSON.stringify 识别\编码
原本这类编码无法读取,现在扩展了识别的编码范围
注:数据库或不能转换icon编码
js
// old
let text = JSON.stringify("\u26D4"); // "�"
// now
let text = JSON.stringify("\u26D4"); // 一个小表情ES2018
【类库】
finally()异步后执行
Promise.prototype.finally()
无论异步成功还是失败,都会执行一遍。避免在then和catch部分写重复代码。
参数:callback回调函数 回调参数:/ 返回值:异步实例
js
const pro = new Promise((resolve) => resolve('a'));
pro
.then(e => console.log(e)) // a
.finally(e => console.log(e)) // undefined,没有参数【语法】
?<>正则分组
正则匹配exec的优化语法,可以直接定义获取元素的组别
js
const regexp = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u;
const result = regexp.exec('2023-01-01');
console.log(result.groups); // {year: '2023', month: '01', day: '01'}